---
title: Multi Modules codegen
---

For multi-modules projects, Apollo Kotlin enables you to define queries in a feature module and reuse fragments and types from another module dependency. This helps with better separation of concerns and build times.

<Note>

This page is for sharing a schema between different modules and defining your `.graphql` operations in different modules. If all your `.graphql` files are in a single module, you can use `apollo-runtime` like any other Kotlin dependency without any of this.

</Note>


## Setup

Multi-modules requires that one and only one module contains a schema. This is the schema that all other modules can reuse. In this document, we'll refer to this module as the "schema module".

In your schema module, opt-in multi-module by generating metadata for use by downstream feature modules:

```kotlin
// schema/build.gradle.kts
apollo {
  service("service") {
    packageName.set("schema")
    
    // Enable generation of metadata for use by downstream modules 
    generateApolloMetadata.set(true)
    
    // If you need to specify the location of your schema files
    schemaFiles.from(/*...*/)
    
    // Scalar mappings and generateDataBuilders must be defined in the schema module
    mapScalar(/*...*/)
    generateDataBuilders.set(true)
    
    // Other options can be different between modules.
    // If you want those options to be applied to all modules, use a convention plugin and shared build logic.
    useSemanticNaming.set(true)
    generateFragmentImplementations.set(true)
  }
}
```

In your feature module, declare your schema module as a dependency:

```kotlin
// feature/build.gradle.kts
apollo {
  // Service names must match
  service("service") {
    packageName.set("feature")
    
    // The 'feature' depends on the 'schema' module
    dependsOn(project(":schema")) // highlight-line
  }
}
```

## Auto-detection of used types

By default, Apollo Kotlin generates all the types in your schema module. This is because there is no way to know in advance what types are going to be used by feature modules. 

For large schemas, this can generate a lot of code and increase your build time significantly. In this case, you can opt in auto-detection of used types. 

This works by splitting the codegen task in different steps so that feature modules can let the schema module know what types are used before actually generating the models. To opt in, call `isADependencyOf()` to establish the bidirectional dependency between your feature module and your schema module:


```kotlin
// schema/build.gradle.kts
apollo {
  service("service") {
    packageName.set("schema")
    generateApolloMetadata.set(true)
    
    isADependencyOf(project(":feature")) // highlight-line
    // list all your feature modules here
    isADependencyOf(project(":feature2"))
    // ...
  }
}
```
Once you opt in auto-detection of used types, it's important that **all** modules are doubly linked like above. If not the feature modules will fail to compile due to some missing schema classes.

## bidirectional parameter (Experimental)

Using `isADependencyOf()` requires listing all your feature modules in your schema module which duplicates code. To keep things minimal and configure the dependency automatically, use `bidirectional = true`:

```kotlin
// feature/build.gradle.kts
apollo {
  service("service") {
    packageName.set("feature")

    // Use `bidirectional` to have the schema module get the used types from this module
    dependsOn(dependencyNotation = project(":schema"), bidirectional = true) // highlight-line
  }
}
```

Also disable generating types in the schema module:

```kotlin
// schema/build.gradle.kts
apollo {
  service("service") {
    packageName.set("schema")
    generateApolloMetadata.set(true)
    
    // Disable generating all types 
    alwaysGenerateTypesMatching.set(emptyList())
  }
}
```

<ExperimentalFeature>

The `bidirectional` parameter is experimental and not compatible with <a href="https://docs.gradle.org/current/userguide/build_environment.html">Gradle project isolation</a>. 

</ExperimentalFeature>

## Optional optimizations

In Android projects, to further improve build times you can consider making your schema module a JVM module instead of an Android library. Since Apollo Kotlin is multiplatform, and Android is capable of depending on JVM-only modules, you can benefit from reducing the amount of work needed to compile the schema module. This is true because JVM modules build faster than Android libraries even with identical source code.  
This is often a good idea because Apollo often happens to be on the critical path of compiling your app. This happens when all the feature modules that use Apollo need to wait for all the type-safe code to be generated before they themselves can start building too.

